#ifndef MESSAGEBOXDISMISSER_H
#define MESSAGEBOXDISMISSER_H

#include "FindWindows.h"

class MessageBoxDismisser
{
	int m_id;
	HWND m_owner;
	HANDLE m_thread;
public:
	MessageBoxDismisser(HWND owner, int id)
		: m_owner(owner)
		, m_id(id)
	{
		m_thread = ::CreateThread(NULL, 0, ThreadProc, reinterpret_cast<LPVOID>(this), 0, NULL);
	}
	virtual ~MessageBoxDismisser()
	{
		::WaitForSingleObject(m_thread, INFINITE);
		::CloseHandle(m_thread);
	}
	
private:
	static DWORD WINAPI ThreadProc(LPVOID lpParameter)
	{
		MessageBoxDismisser * pThis = reinterpret_cast<MessageBoxDismisser*>(lpParameter);
		pThis->ThreadProc();
		return 0;
	}
	void ThreadProc()
	{
		HWND hwndPopUp = NULL; // pop up window
		for(int i=0; i<1000; i+=10) // wait for at most 1 second
		{
			hwndPopUp = GetWindow (m_owner, GW_ENABLEDPOPUP);
			if (hwndPopUp) {
				if (hwndPopUp != m_owner) {
					break;
				}
			}
			::Sleep (10);
		}
		if (hwndPopUp == NULL || hwndPopUp == m_owner)
		{	// message box didn't pop up after a whole second

			// last chance:  try enuming all windows trying to find a window owned by m_owner
			class OwnedPredicate
			{
				HWND m_owner;
			public:
				OwnedPredicate(HWND owner) : m_owner(owner) {}
				bool operator()(HWND hwnd) const
				{
					return m_owner == ::GetWindow(hwnd, GW_OWNER);
				}
			} op(m_owner);
		
			hwndPopUp = ::FindDesiredWindow(op);
			if (hwndPopUp == NULL)
				return; // still can't find it.
		}

		FoundMessageBox(hwndPopUp); // let derived classes know

		CWindow mb(hwndPopUp);

		HWND hwndButton = mb.GetDlgItem(m_id);
		if ((hwndButton == NULL) && (m_id == IDOK)) {
			// if there's only 1 button, "they" (Windows) change its id to IDCANCEL;
			// so, if IDOK doens't work, try IDCANCEL
			hwndButton = mb.GetDlgItem(IDCANCEL);
		}
		if (hwndButton != NULL) {
			::SetActiveWindow(hwndButton);
			::SendMessage(hwndButton, BM_CLICK, 0, 0L);
			::SendMessage(hwndButton, BM_CLICK, 0, 0L); // twice for good measure.
		}
	}

	virtual void FoundMessageBox(HWND ) {}
};


class ExamineMessageBox : public MessageBoxDismisser
{
	CString& m_text;
	CString& m_caption;
	CString& m_okButton;
public:
	ExamineMessageBox(CString& text, CString& caption, CString& okButton, HWND owner, int id)
		: m_text(text)
		, m_caption(caption)
		, m_okButton(okButton)
		, MessageBoxDismisser(owner, id)
	{}
private:
	virtual void FoundMessageBox(HWND hwnd)
	{
		CWindow mb(hwnd);
		mb.GetWindowText(m_caption);
		mb.GetDlgItemText(0xFFFF, m_text);
		mb.GetDlgItemText(IDCANCEL, m_okButton); // NOTE:  this is correct!  From digging into the Windows sources, I found that if there is a single button on the messagebox, and it's IDOK, they swap it with the IDCANCEL id, for some unknown reason.
	}
};

#endif